package myCobra

import (
	"fmt"
	"os"
	"strings"

	flag "github.com/spf13/pflag"
)

type Command struct {
	// 命令名称，根命令可任意取
	Use string
	// 	命令描述，-h显示的帮助信息
	Short string
	Long  string
	// 执行的操作
	Run func(cmd *Command, args []string)
	// 存储命令
	commands []*Command
	// 子命令
	subCom *Command
	// 父命令
	parentCom *Command
	// 命令参数
	args []string
	// 标志选项
	pflags *flag.FlagSet
}

func (c *Command) AddCommand(cmds ...*Command) {
	for _, x := range cmds {
		if x == c {
			panic("Command can't be a child of itself")
		}
		x.parentCom = c
		c.commands = append(c.commands, x)
	}
}

func (c *Command) Execute() error {
	if c == nil {
		panic("Called Execute() on a nil Command")
	}
	// 执行到根命令
	if c.parentCom == nil {
		ParseArgs(c, os.Args[1:])
	}
	c.execute()
	return nil
}

func (c *Command) execute() {
	// 子命令为空则执行自身
	if c.subCom == nil {
		if c.parentCom == nil {
			for _, v := range c.args {
				if v == "-h" || v == "--help" {
					c.Print_help()
					return
				}
			}
		}

		c.Run(c, c.args)
		return
	}
	c.subCom.execute()
}

// 递归获取命令对应参数
func ParseArgs(c *Command, args []string) {
	if len(args) < 1 {
		return
	}

	for _, v := range c.commands {
		// 找到当前命令
		if v.Use == args[0] {
			c.args = args[:1]
			c.subCom = v
			v.parentCom = c
			ParseArgs(v, args[1:])
			return
		}
	}
	c.args = args
	// 添加选项参数
	c.PersistentFlags().Parse(c.args)
}

// 添加识别标志/选项
func (c *Command) PersistentFlags() *flag.FlagSet {
	if c.pflags == nil {
		c.pflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError)
	}
	return c.pflags
}

// 返回命令名
func (c *Command) Name() string {
	name := c.Use
	i := strings.Index(name, " ")
	if i >= 0 {
		name = name[:i]
	}
	return name
}

// -h打印输出帮助信息
func (c *Command) Print_help() {
	fmt.Printf("%s\n\n", c.Long)
	fmt.Printf("Usage:\n")
	fmt.Printf("\t%s [flags]\n", c.Name())
	if len(c.commands) > 0 {
		fmt.Printf("\t%s [command]\n\n", c.Name())
		fmt.Printf("Available Commands:\n")
		for _, v := range c.commands {
			fmt.Printf("\t%-10s%s\n", v.Name(), v.Short)
		}
	}

	fmt.Printf("\nFlags:\n")

	c.PersistentFlags().VisitAll(func(flag *flag.Flag) {
		fmt.Printf("\t-%1s, --%-6s %-12s%s (default \"%s\")\n", flag.Shorthand, flag.Name, flag.Value.Type(), flag.Usage, flag.DefValue)
	})
	//help选项不存在于选项集中，但却可以使用。当使用help选项时，默认的pflag库会打印出正确的使用方法，在
	//这里我们并不需要，所以对flag.go作了轻微修改，将defaultUsage的函数体全部注释掉
	fmt.Printf("\t-%1s, --%-19s%s%s\n", "h", "help", "help for ", c.Name())
	fmt.Println()
	if len(c.commands) > 0 {
		fmt.Printf("Use \"%s [command] --help\" for more information about a command.\n", c.Name())
	}
	fmt.Println()
}
